package com.googlecode.ascrblr.api.radio.xspf;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.schueth.lastfm.LastfmSession;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XSPF {
	
	/** 
	 * Logger instance. 
	 */
	public static final Logger logger = Logger.getLogger(XSPF.class.getName());
	
	/** Builder Factory */
	private DocumentBuilderFactory builderFactory;
	
	/** Document builder */
	private DocumentBuilder builder;
    
	/** Playlist document */
	private Document xspf;
	
	/** XPatch query */
	private XPath xpath;
	
	/** Playlist version */
	private String version;
	
	/** Playlist title */
	private String title;
	
	/** Playlist creator */
	private String creator;
	
	/** Number of skippable tracks */
	private Integer skipCount;
	
	/** Playlist tracks */
	private List<BufferedTrack> bufferdtracklist;
	
	private LastfmSession session;
	/**
	 * Creates a XSPF playlist out of a valid <code>InputStream</code>
	 * @param is
	 * @throws ParserConfigurationException
	 * @throws IOException
	 * @throws SAXException
	 * @throws XPathExpressionException
	 */
	public XSPF(InputStream is, LastfmSession session) throws ParserConfigurationException, IOException, 
		SAXException, XPathExpressionException {	
		this.session = session;
		parse(is);
	}
	
	/**
	 * Creates a XSPF playlist out of a valid <code>Document</code>
	 * 
	 * @param doc
	 * @throws ParserConfigurationException
	 * @throws IOException
	 * @throws SAXException
	 * @throws XPathExpressionException
	 */
	public XSPF(Document doc,LastfmSession session) throws ParserConfigurationException, IOException, 
		SAXException, XPathExpressionException  {
		this.session = session;
		parse(doc);
	}

	/**
	 * Parses a playlist <code>InputStream</code>
	 * 
	 * @param in
	 * @throws ParserConfigurationException
	 * @throws IOException
	 * @throws SAXException
	 * @throws XPathExpressionException
	 */
	private void parse(InputStream in) throws ParserConfigurationException, IOException, 
		SAXException, XPathExpressionException  {
		
		builderFactory = DocumentBuilderFactory.newInstance();
		builderFactory.setNamespaceAware(true);
		builder = builderFactory.newDocumentBuilder();	
		xspf = builder.parse( in );
		parse(xspf);
	
	}

	/**
	 * Parses a playlist <code>Document</code>
	 * 
	 * @param doc
	 * @throws ParserConfigurationException
	 * @throws IOException
	 * @throws SAXException
	 * @throws XPathExpressionException
	 */
	private void parse(Document doc) throws ParserConfigurationException, IOException, 
		SAXException, XPathExpressionException  {

		xpath = XPathFactory.newInstance().newXPath();
		xspf = doc;
		
		version = (String) xpath.evaluate(XSPFElement.PLAYLIST_VERSION.getXPath(), xspf, XPathConstants.STRING);		
        title = (String) xpath.evaluate(XSPFElement.PLAYLIST_TITLE.getXPath(), xspf, XPathConstants.STRING);
        try {
        	title = URLDecoder.decode(title, "UTF-8");
        }catch(UnsupportedEncodingException e){
        	//ignore and leave undecoded
        }
        creator = (String) xpath.evaluate(XSPFElement.PLAYLIST_CREATOR.getXPath(), xspf, XPathConstants.STRING);     
        
        NodeList tracks = (NodeList) xpath.evaluate(XSPFElement.PLAYLIST_TRACKLIST.getXPath(), xspf, XPathConstants.NODESET);
        for(int i=0; i<tracks.getLength(); i++) {

        	
        	
        	if(bufferdtracklist == null) {
        		bufferdtracklist = new ArrayList<BufferedTrack>();
        	}
        	
        	Node trackNode = tracks.item(i);
        	
        	BufferedTrack bt = new BufferedTrack(trackNode,session);
        	Track t = new Track(trackNode);
        	
        	bufferdtracklist.add(bt);
        	
        }
        
        String skipCountExpr = ((String) xpath.evaluate(XSPFElement.PLAYLIST_SKIPCOUNT.getXPath(), xspf, XPathConstants.STRING));
        skipCount = (!"".equals(skipCountExpr)) ? Integer.valueOf( skipCountExpr ) : bufferdtracklist.size();
        
	}

	/**
	 * Gets playlist version
	 * 
	 * @return
	 */
	public String getVersion() {
		return version;
	}

	/** 
	 * Gets playlist title
	 * 
	 * @return
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * Gets plalist creator
	 * 
	 * @return
	 */
	public String getCreator() {
		return creator;
	}
	
	/**
	 * Returns number of skippable tracks
	 * 
	 * @return
	 */
	public Integer getSkipCount() {
		return skipCount;
	}


	/**
	 * Returns playlist tracks
	 * 
	 * @return <code>Track</code> entries
	 */
	public List<BufferedTrack> getBufferdTracklist() {
		return bufferdtracklist;
	}
	
	@Override
	public String toString() {
		
		return "XSPF {\n" +
				"version=" + version + ",\n" +
				"creator=" + creator + ",\n" +
				"skipCount=" + skipCount +",\n" +
				"tracks=" + bufferdtracklist.size() + "\n" +
				"};";
		
	}
	
}
